package com.hb.util;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hb.commons.MsgEnum;
import com.hb.commons.ResponseDto;
import com.hb.commons.StringRedisService;
import com.hb.config.shiro.JwtToken;
import com.hb.demo.entity.AdminUser;
import com.hb.demo.entity.LoginModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.stream.Collectors;

@Slf4j
public class ContextUtil {

    /**
     * 获取当前线程下的request对象
     * 此方法尽量只在controller层调用
     *
     * @return
     */
    public static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
    }

    /**
     * 获取request body中的整个json格式参数对象
     *
     * @return
     */
    public static JSONObject getQueryJSON() {
        HttpServletRequest request = getRequest();
        String queryStr;
        JSONObject params = null;
        try {
            queryStr = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
            if (StrUtil.isEmpty(queryStr)) {
                return JSONUtil.createObj();
            }
            params = JSONUtil.parseObj(queryStr);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return params;
    }

    /**
     * 获取request body中的json格式参数中指定key的值
     *
     * @param key
     *
     * @return
     */
    public static Object get(String key) {
        JSONObject params = getQueryJSON();
        return params.get(key);
    }

    /**
     * 获取request body中的json格式参数中指定key的值
     *
     * @param key
     *
     * @return 返回int类型
     */
    public static Integer getInt(String key) {
        Object value = get(key);
        if (value == null) {
            return null;
        }
        if (NumberUtil.isNumber(value.toString())) {
            return Integer.parseInt(value.toString());
        }
        return null;
    }

    /**
     * 获取request body中的json格式参数中指定key的值
     *
     * @param key
     *
     * @return 返回String类型
     */
    public static String getStr(String key) {
        Object value = get(key);
        return value == null ? null : value.toString();
    }

    /**
     * 获取当前请求中的token
     *
     * @return
     */
    public static String getToken() {
        HttpServletRequest request = getRequest();
        return request.getHeader(JwtUtils.X_ACCESS_TOKEN);
    }

    /**
     * 获取当前用户信息
     * 该方法不会返回null
     *
     * @return
     */
    public static AdminUser getUserEntity() {
        AdminUser currentUser = getUser();
        if (currentUser == null) {
            return new AdminUser();
        }
        return currentUser;
    }

    /**
     * 获取当前用户信息
     *
     * @return
     */
    public static AdminUser getUser() {
        String token = getToken();
        if (StrUtil.isEmpty(token)) {
            return null;
        }
        String uname = JwtUtils.getUsername(token);
        if (StrUtil.isEmpty(uname)) {
            return null;
        }

        StringRedisService redisService = SpringUtil.getBean(StringRedisService.class);
        String loginModelJSON = redisService.get(JwtUtils.PREFIX_USER_TOKEN + uname);

        if (StrUtil.isEmpty(loginModelJSON)) {
            return null;
        }

        LoginModel model = JSONUtil.toBean(loginModelJSON, LoginModel.class);
        if (model == null) {
            return null;
        }
        return model.getUser();
    }

    /**
     * 获取当前用户的userId
     *
     * @return
     */
    public static Long getUserId() {
        String token = getToken();
        if (StrUtil.isEmpty(token)) {
            return null;
        }
        return JwtUtils.getUserId(token);
    }

    /**
     * 统一登录
     *
     * @param token
     *
     * @return
     */
    public static ResponseDto login(JwtToken token) {
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (UnknownAccountException e) { // 用户名不存在
            log.error(e.getMessage());
            return ResultUtil.msg(MsgEnum.USERNAME_NOT_FOUND);
        } catch (AuthenticationException e) { // 可能是用户名密码错误
            log.error(e.getMessage());
            return ResultUtil.msg(MsgEnum.WRONG_USERNAME_PASSWORD);
        }

        String uname = token.getUsername();

        // 登录信息存入redis
        LoginModel model = LoginModel.get(token.getUserEntity(), token.getToken());
        StringRedisService redisService = SpringUtil.getBean(StringRedisService.class);
        redisService.set(JwtUtils.PREFIX_USER_TOKEN + uname, model.toString(), JwtUtils.EXPIRE);
        return null;
    }

    /**
     * 退出登录
     *
     * @return
     */
    public static boolean logout() {
        String token = getToken(); // 获取token
        if (StrUtil.isEmpty(token)) {
            return false;
        }
        // 当前登录用户的用户名
        String uname = JwtUtils.getUsername(token);
        if (StrUtil.isEmpty(uname)) {
            return false;
        }
        // 删除redis记录
        StringRedisService redisService = SpringUtil.getBean(StringRedisService.class);
        if (redisService != null) {
            String key = JwtUtils.PREFIX_USER_TOKEN + uname;
            return redisService.delete(key);
        }
        return false;
    }

    public static void preHandle(HttpServletResponse response, String origin) {
        // 设置跨域访问(限制跨域时在网关处理, 这里不做处理)
/*        if (ArrayUtil.contains(ALLOW_ORIGIN, origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
        }*/
        response.setHeader("Access-control-Allow-Origin", "*");

        // response.setHeader("Access-Control-Allow-Credentials", "false");

        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Expose-Headers", "*");
        response.setHeader("server", "");

        response.setHeader("Access-Control-Max-Age", "86400");

        response.setHeader("XDomainRequestAllowed", "1");
    }
}
